#pragma once
#include "stdafx.h"
#include <windowsx.h>
#include <commctrl.h>
#include <types.h>
#include "gstring.h"
#include "winapi.h"

////////////////////////////////////
class CWnd
{
public:
	CWnd();

	operator HWND() const {return hWnd;}
	virtual inline HWND GetWnd() {return hWnd;}

	virtual int PreTranslateMessage(MSG* pMsg) { return 0; }
	virtual	LPTSTR RegisterDefaultClass(LPCTSTR lpClassName=NULL, DWORD dwStyle=0, LPCTSTR lpszIcon=0, LPCTSTR lpszCursor=0);
	static LRESULT CALLBACK Procedure(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { return (LRESULT)0; }

#pragma warning(push)
#pragma warning(disable:4312)
#pragma warning(disable:4244)
	static CWnd* GetWindowPtr(HWND hWnd) { return reinterpret_cast<CWnd*>(::GetWindowLongPtr(hWnd,GWL_USERDATA)); }
	static void SetWindowPtr(HWND hWnd, CWnd *pWnd) { ::SetWindowLongPtr(hWnd,GWL_USERDATA,reinterpret_cast<LONG_PTR> (pWnd)); }
#pragma warning(pop)

	inline void EnableWindow(BOOL bEnable=TRUE) { ::EnableWindow(GetWnd(),bEnable); }
	inline void EnableWindow(HWND hwnd, BOOL bEnable=TRUE) { ::EnableWindow(hwnd,bEnable); }
	inline void GetClientRect(RECT *rect) { ::GetClientRect(*this,rect); }
	inline void GetClientRect(HWND hWnd, RECT* rect) { ::GetClientRect(hWnd,rect); }
	//inline void GetFocus() { hWnd=::GetFocus (); }
	inline HWND GetParent() { return hParent; }
	inline DWORD GetStyle() { return GetWindowLongPtr(hWnd, GWL_STYLE); }
	inline HWND GetTopWindow() { return ::GetTopWindow(*this); }
	inline void SetFocus() { ::SetFocus(*this); }
	inline void SetFocus(HWND hwnd) { ::SetFocus(hwnd); }
	inline void SetStyle(DWORD dwStyle) { ::SetWindowLongPtr(*this, GWL_STYLE, dwStyle); }
	inline BOOL SetWindowText(LPCTSTR lpString) { return ::SetWindowText(*this,lpString); }
	inline int MessageBox(LPCTSTR lpText, LPCTSTR lpCaption=NULL, UINT uType=MB_OK) { return ::MessageBox(hWnd,lpText,lpCaption,uType); }

	// prototypes for default messages
	virtual UINT OnCommand(WPARAM wParam, LPARAM lParam) { return 0; }
	virtual void OnCreate(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {}
	virtual LRESULT OnMessage(UINT iMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(*this,iMsg,wParam,lParam); }
	//virtual void OnKeyDown(WPARAM wParam, LPARAM lParam) {}
	virtual void OnKillFocus() {}
	virtual void OnVScroll(UINT nSBCode, UINT nPos) {}
	virtual void OnHScroll(UINT nSBCode, UINT nPos) {}
	virtual void OnInitMenuPopUp(HMENU hMenu, LPARAM lParam) {}
	virtual void OnDrawItem(LPDRAWITEMSTRUCT lpmis) {}
	virtual void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpmis) {}
	virtual void OnLButtonDown(int xPos, int yPos) {}
	virtual void OnLButtonUp(int xPos, int yPos) {}
	virtual void OnMButtonDown(int xPos, int yPos) {}
	virtual void OnMButtonUp(int xPos, int yPos) {}
	virtual void OnNCPaint(HDC hdc) {}
	virtual void OnPaint() {}
	virtual void OnRButtonDown(int xPos, int yPos) {}
	virtual void OnRButtonUp(int xPos, int yPos) {}
	virtual void OnMouseMove(int xPos, int yPos) {}
	virtual void OnMouseWheel(WORD fwKeys, short zDelta, int xPos, int yPos) {}
	virtual void OnSize(int cx, int cy) {}
	virtual void OnSetFocus() {}

	BOOL SubMenuSystem(HMENU hPopupMenu);
	void Invalidate(BOOL bErase=TRUE);
	GString GetWindowText();
	GString GetWindowText(UINT uID);
	void SetDlgItem(HWND hWnd, UINT uID);
	void SetWindowPos(HWND hWndInsertAfter, int x, int y, int w, int h);
	void SetWindowSize(int w, int h);
	void ShowWindow(int nCmdShow);
	inline BOOL ShowWindow(HWND hwnd, int nCmdShow) { return ::ShowWindow(hwnd,nCmdShow); }

protected:
	HWND hWnd, hParent;
	UINT uID;
};

////////////////////////////////////
class CScrollBar : public CWnd
{
public:
	enum Scroll
	{
		Horizontal=SBS_HORZ,
		Vertical=SBS_VERT
	};

	HWND Create(HWND hWndParent, Scroll type)
	{
		hParent=hWndParent;
		sType=type;
		nBar= SB_CTL | (sType==Vertical ? SB_VERT : SB_HORZ);
		return hWnd=CreateWindow(_T("scrollbar"), NULL, WS_CHILD | WS_VISIBLE | type, 0,0,0,0, hParent, (type==Horizontal ? (HMENU)1 : (HMENU)2), GetAppInstance(), NULL);
	}

	inline BOOL SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw=TRUE) { return ::SetScrollRange(*this,nBar,nMinPos,nMaxPos,bRedraw); }
	inline BOOL GetScrollRange(int &nMinPos, int &nMaxPos) { return ::GetScrollRange(*this,nBar,&nMinPos,&nMaxPos); }
	inline int SetScrollPos(int nPos, BOOL bRedraw=TRUE) { return ::SetScrollPos(*this,nBar,nPos,bRedraw); }
	int SetScrollInfo(UINT fMask, int nMin, int nMax, int nPage, int nPos)
	{
		SCROLLINFO si={0};
		si.cbSize = sizeof(si);
		si.fMask  = fMask;
		si.nMin   = nMin;
		si.nMax   = nMax;
		si.nPage  = nPage;
		si.nPos   = nPos;
		return ::SetScrollInfo(*this,nBar,&si,TRUE);
	}

private:
	Scroll sType;
	int nBar;
};

////////////////////////////////////
class CScrollWnd : public CWnd
{
public:
	CScrollBar m_Scroll_h, m_Scroll_v;

	inline HWND SetVertScrollbar() { return m_Scroll_v.Create(hParent, CScrollBar::Vertical); }
	inline HWND SetHorzScrollbar() { return m_Scroll_h.Create(hParent, CScrollBar::Horizontal); }
};

////////////////////////////////////
class CDialogCtrl : public CWnd
{
public:
	virtual void SetDlgItem(HWND hWnd, UINT uID);

	static LRESULT CALLBACK Procedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	virtual LRESULT OnMessage(UINT iMsg, WPARAM wParam, LPARAM lParam) { return 0; }

	WNDPROC oldProcedure;
};

////////////////////////////////////
class CButton : public CWnd
{
public:
	inline int GetCheck() { return Button_GetCheck(*this); }
	inline void SetCheck(int check) { Button_SetCheck(*this,check); }

	inline int GetState() { return Button_GetState(*this); }
	inline void SetState(int state) { Button_SetState(*this,state); }
};

////////////////////////////////////
class CEditCtrl : public CWnd
{
public:
	inline GString GetText() { return GetWindowText(); }
	inline void SetText(LPCTSTR text) { SetWindowText(text); }
	inline void GetSelection(int &start, int &end) { ::SendMessage(*this,EM_GETSEL,(WPARAM)&start,(LPARAM)&end); }

	u32 GetValue();
	void SetValue(u32 value, bool has_sign=false);
};

////////////////////////////////////
class CSpinControl : public CWnd
{
public:
	void SetRange(short low, short high);
	void SetRange32(int low, int high);
};

////////////////////////////////////
class CListCtrl : public CWnd
{
public:
	inline void DeleteItem(int index) { ListView_DeleteItem(*this, index); }
	void InsertItem(int index, LPCTSTR text);
	void SetItemText(int index, LPCTSTR text);
	void SetType(int type);

	// combo box style messages for simple lists
	inline int GetCurSel() { return (int)SendMessage(*this,LVM_GETNEXTITEM,-1,LVNI_FOCUSED); }
	inline int GetCount() { return (int)ListView_GetItemCount(*this); }
	void SetCurSel(int index);	// use -1 to deselect

	enum LIST_TYPES
	{
		LT_ICON_SMALL,
		LT_ICON_BIG,
		LT_REPORT,
		LT_LIST
	};
};

////////////////////////////////////
class CComboBoxCtrl : public CWnd
{
public:
	inline void AddString(LPCTSTR text) { SendMessage(*this,CB_ADDSTRING,0,(LPARAM)text); }
	inline int GetCurSel() { return (int)SendMessage(*this,CB_GETCURSEL,0,0); }
	inline void SetCurSel(int index) { SendMessage(*this,CB_SETCURSEL,index,0); }
	inline void Reset() { SendMessage(*this,CB_RESETCONTENT,0,0); }
};
